package com.message.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.base.model.R;
import com.base.utils.VideoUtil;
import com.j256.simplemagic.ContentInfo;
import com.j256.simplemagic.ContentInfoUtil;
import com.message.mapper.MessageMapper;
import com.message.model.Message;
import com.message.service.MessageService;
import io.minio.GetObjectArgs;
import io.minio.MinioClient;
import io.minio.RemoveObjectArgs;
import io.minio.UploadObjectArgs;
import io.minio.errors.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.List;
import java.util.UUID;

/**
 * @Author: 小何
 * @Description: TODO
 * @DateTime: 2023/10/23 16:40
 **/
@Service
@Slf4j
public class MessageServiceImpl extends ServiceImpl<MessageMapper, Message>implements MessageService {

    private static final String BUCKET_VIDEO = "video";

    @Autowired
    private MinioClient minioClient;

    @Autowired
    private MessageMapper messageMapper;

    @Override
    public R<String> addMessage(Message message) {
        this.save(message);
        return R.success("消息添加成功");
    }

    @Override
    public List<Message> selectTaskByShardIndex(Integer shardIndex, Integer shardTotal, Integer count) {
        return messageMapper.selectTaskByShardIndex(shardIndex,shardTotal,count);
    }

    @Override
    public Boolean updateTranscodeStatus(Integer messageId) {
        UpdateWrapper<Message>uw=new UpdateWrapper<>();
        uw.set("transcode",1)
                .eq("Id",messageId);
        return  this.update(uw);
    }

    /**
     * 视频转码
     *
     * @param MD5
     * @return
     */
    @Override
    public boolean transcode(String MD5, String suffix) {
        VideoUtil videoUtil=new VideoUtil();
        try {
            File originFile = downFileFromMinio(MD5, suffix);
            File tempFile = File.createTempFile(UUID.randomUUID().toString().replace("-", ""), ".mp4");
            videoUtil.videoConvert(originFile.getAbsolutePath(),tempFile.getAbsolutePath());
            String targetFileName=tempFile.getName();
            String targetSuffix=targetFileName.substring(targetFileName.lastIndexOf('.'));
            String mimeType = getMimeType(targetSuffix);
            String objectName=getFilePathByMd5(MD5,targetSuffix);
            String originName=getFilePathByMd5(MD5,suffix);
            boolean b = uploadFileToMinio(tempFile.getAbsolutePath(), mimeType, BUCKET_VIDEO, objectName);
            //todo:删除原视频
            RemoveObjectArgs removeObjectArgs= RemoveObjectArgs.builder().bucket(BUCKET_VIDEO).object(originName).build();
            minioClient.removeObject(removeObjectArgs);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }


    private boolean uploadFileToMinio(String filePath, String mimeType, String bucket, String objectName) {
        try {
            UploadObjectArgs uploadObjectArgs = UploadObjectArgs.builder()
                    .bucket(bucket)//桶
                    .filename(filePath) //指定本地文件路径
                    .object(objectName)//对象名 放在子目录下
                    .contentType(mimeType)//设置媒体文件类型
                    .build();
            //上传文件
            minioClient.uploadObject(uploadObjectArgs);
            log.debug("上传文件到minio成功,bucket:{},objectName:{}", bucket, objectName);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            log.error("上传文件出错,bucket:{},objectName:{},错误信息:{}", bucket, objectName, e.getMessage());
        }
        return false;
    }

    private File downFileFromMinio(String MD5, String suffix) {
        try {
            String originUrl = getFilePathByMd5(MD5, suffix);
            GetObjectArgs args = GetObjectArgs.builder().bucket(BUCKET_VIDEO).object(originUrl).build();
            InputStream inputStream = minioClient.getObject(args);
            if (inputStream == null) {
                return null;
            }
            File file = File.createTempFile(UUID.randomUUID().toString().replace("-", ""), suffix);
            FileOutputStream outputStream = new FileOutputStream(file);
            IOUtils.copy(inputStream, outputStream);
            return file;
        } catch (ErrorResponseException | InsufficientDataException | InternalException | InvalidKeyException | InvalidResponseException | IOException | NoSuchAlgorithmException | ServerException | XmlParserException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 根据扩展名获取文件MimeType
     *
     * @param extension 文件拓展名
     * @return mimeType
     */
    private String getMimeType(String extension) {
        if (extension == null) {
            extension = "";
        }
        //根据扩展名取出mimeType
        ContentInfo extensionMatch = ContentInfoUtil.findExtensionMatch(extension);
        String mimeType = MediaType.APPLICATION_OCTET_STREAM_VALUE;//通用mimeType，字节流
        if (extensionMatch != null) {
            mimeType = extensionMatch.getMimeType();
        }
        return mimeType;

    }


    /**
     * 通过Md5得到文件存储minio中的地址
     *
     * @param fileMd5 文件id即md5值
     * @param fileExt 文件扩展名
     * @return 文件名
     */
    private String getFilePathByMd5(String fileMd5, String fileExt) {
        return fileMd5.charAt(0) + "/" + fileMd5.charAt(1) + "/" + fileMd5 + "/" + fileMd5 + fileExt;
    }

}
